package com.itjeffrey.autocode.security;

import com.alibaba.fastjson.JSON;
import com.itjeffrey.autocode.common.ACContext;
import com.itjeffrey.autocode.common.Result;
import com.itjeffrey.autocode.config.SecurityProperties;
import com.itjeffrey.autocode.constant.SysConstant;
import com.itjeffrey.autocode.entity.RoleInfoTbEntity;
import com.itjeffrey.autocode.enums.ExceptionEnum;
import com.itjeffrey.autocode.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 资源权限拦截器
 * 1.接口资源
 *   当前请求URI与当前用户所拥有的接口资源URL进行比较
 * 2.菜单资源
 *   当前资源名与当前用户所拥有的的资源名进行比较
 *   注：菜单资源主要由前端实现，用户开始登录时调用后台接口获取该用户所有菜单资源，然后加载对应的菜单目录
 * @From: Jeffrey
 * @Date: 2021/3/28
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    public static final Logger log = LoggerFactory.getLogger(JwtInterceptor.class);

    @Autowired
    private UserService userService;
    @Autowired
    private SecurityProperties securityProperty;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        log.debug("JwtInterceptor preHandle is handling, requestURI:{}", requestURI);
        //获取用户上下文信息
        JwtUserDetails userContext = ACContext.getUserContext();
        if(userContext == null){
            return false;
        }
        String loginName = userContext.getUsername();
        String userName = userService.getUserNameByLoginName(loginName);
        //管理员用户可以授权访问任何资源
        if (securityProperty.isEnableAdmin() && securityProperty.getAdminAcc().equals(userName)) {
            log.debug("[Admin] account access any resource release!");
            return true;
        }
        //角色为管理员admin的直接放行
        Result result = userService.queryRoleInfosByLoginName(loginName);
        if(result == null && result.getData() == null){
            log.warn("[{}] query no roles!", loginName);
        }
        List<RoleInfoTbEntity> list = (List<RoleInfoTbEntity>) result.getData();
        long size = list.stream().filter(roleInfoTbEntity -> "admin".equals(roleInfoTbEntity.getRoleName())).count();
        if(size > 0){
            log.debug("[admin] role access any resource release!");
            return true;
        }

        //非管理员账号非管理员角色判断该用户是否有访问该资源的权限
        if(userService.hasResource(userName, requestURI, SysConstant.RES_TYPE_JK)){
            log.debug("[{}] access resource [{}] release!", userName, requestURI);
            return true;
        }
        //TODO 菜单资源权限判断
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(JSON.toJSONString(Result.fail(ExceptionEnum.NO_AUTH_TO_VISIT)));
        log.warn("[{}] has no auth to access resource [{}]",userName, requestURI);
        return false;
    }
}
